#ifndef COMMON_H_INCLUDED
#define COMMON_H_INCLUDED

#include <allegro.h>
#include <math.h>
#include "Singleton.h"
#include "algif/src/gif.h"

typedef unsigned char  uchar;
typedef unsigned int   uint;
typedef unsigned short ushort;

enum {
    DIR_LEFT = 0,
    DIR_RIGHT = 1,

    MAP_W = 128,
    MAP_H = 128,

    IN_BOX_MINX = 5,
    IN_BOX_MAXX = MAP_W - 20,
    IN_BOX_MINY = 5,
    IN_BOX_MAXY = MAP_H - 20,

    NONMONSTER = 0xffff,

    MAX_TILE_FILES = 4,

    screen_startx = 384,
    screen_starty = 16,
    SEP = 5,
    BODY_MAX = 6,
    INV_ROW = 5,
    INV_COL = BODY_MAX,
    INV_TILE_W = 32,
    INV_TILE_H = 32,
    INV_WIDTH = INV_COL *(INV_TILE_W+SEP)+SEP,
    INV_HEIGHT = (1+INV_ROW)*(INV_TILE_H+SEP)+SEP,
};

struct Rect {
    short x, y;
    short w, h;
    Rect() :
        x(0), y(0), w(0), h(0) {}
    Rect(short x_, short y_) :
        x(x_), y(y_), w(0), h(0) {}
    Rect(short x_, short y_, short w_, short h_) :
        x(x_), y(y_), w(w_), h(h_) {}
    bool operator == (const Rect &r) const {
        return r.x == x && r.y == y;
    }
    bool operator != (const Rect &r) const {
        return !(r == *this);
    }
    bool inRect(short x_, short y_) {
        return (x <= x_ && x_ <= x+w && y <= y_ && y_ <= y+h);
    }
    bool operator < (const Rect &r) const {
#define CMP(m, r) if (m < r.m) return true; if (m > r.m) return false
        CMP(x, r);
        CMP(y, r);
        CMP(w, r);
        CMP(h, r);
#undef CMP
        return false;
    }
    double distance(const Rect &r) const
    {
        double dx = x - r.x;
        double dy = y - r.y;
        return sqrt(dx*dx + dy*dy);
    }

};

class Live
{
public:
        Live() : m_hp(0), m_mp(0), m_maxhp(0), m_maxmp(0), m_dead(true)
        {
        }
        Live(int hp, int mp) : m_hp(hp), m_mp(mp), m_maxhp(hp), m_maxmp(mp), m_dead(false)
        {
        }
        const int Hp(int hp = 0)
        {
            if (hp) m_hp = hp;
            return m_hp;
        }
        const int Mp(int mp = 0)
        {
            if (mp) m_mp = mp;
            return m_mp;
        }
        void changeHp(int v)
        {
            if (m_dead)
            {
                m_hp = 0;
                return;
            }
            m_hp += v;
            if (m_hp > m_maxhp)
                m_hp = m_maxhp;
            if (m_hp < 0)
            {
                m_hp = 0;
                m_dead = true;
                return;
            }
        }
        void changeMp(int v)
        {
            if (m_dead)
                return;
            m_mp += v;
            if (m_mp > m_maxmp)
                m_mp = m_maxmp;
            if (m_mp < 0)
                m_mp = 0;
        }
        void setMaxHp(int hp)
        {
            m_maxhp = hp;
        }
        void sethp(int hp)
        {
            m_hp = hp;
            changeHp(0);
        }
        void setmp(int mp)
        {
            m_mp = mp;
            changeMp(0);
        }
        void setMaxMp(int mp)
        {
            m_maxmp = mp;
        }
        bool dead () const
        {
            return m_dead;
        }
        void setlive(bool flag)
        {
            m_dead = flag;
        }
private:
        int m_hp, m_mp;
        int m_maxhp, m_maxmp;
        bool m_dead;
};


struct Config {
    Config();
    void fresh_position(short x, short y);
    int console_fg_color;
    int console_bg_color;
    int inventory_bg_color;
    int inventory_fg_color;
    short scr_startx;
    short scr_starty;
    short player_x;
    short player_y;
    short player_mapx;
    short player_mapy;
    short direction;
    short cur_x;
    short cur_y;
    int   walktick;
};

#include <string>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using std::string;
using std::vector;
using std::map;
using std::set;

inline int atoi(const string &s) { return atoi(s.c_str()); }
string &trim(string &str);
string &replaceAll(string s, const string &find, const string &repl);
void split(vector<string> &ret, const char *buf, char sep);

void screenxy_to_mapxy(short sx, short sy, short &mx, short &my);
void mapxy_to_screenxy(short mx, short my, short &sx, short &sy);
void masked_blit(BITMAP *source, BITMAP *dest, const Rect &pos);

template <typename T>
struct Deleter {
    void operator()(T * const &t) const {
        delete t;
    }
};

class GifAnimation {
public:
	struct LoadGifFailed {};
	GifAnimation (const char *filename);
	~GifAnimation ();
	bool  NextFrame();
	inline BITMAP *getCurFrame() { return m_frames[m_cur]; }
	inline void setloops(int loop) { m_loops = loop; }
	inline int  getloops() { return m_loops; }

private:
	BITMAP **m_frames;
	int     *m_durations;
	int      m_nframe;
	int      m_cur;
	int      m_loops;
};

#endif // COMMON_H_INCLUDED
